#include "ScnsTcs3472.c.h"

#if defined(SCNS_TCS3472_ENABLE)&&SCNS_TCS3472_ENABLE==1

//@scnsBsp:https://gitee.com/huoxingdawang/scnsDemos-MM32F3277_seekfree/tree/master/Libraries/scnsBsp/MM32F3277_seekfree/

#include "ScnsTimer.h"
#include "ScnsMath.h"

static struct
{
    uint8 inited;
}rd[SCNS_TCS3472_MAX];

ScnsTcs3472Result scnsTcs3472Result[SCNS_TCS3472_MAX];

#define TCS3472_ENABLE           (0x00)
#define TCS3472_ENABLE_AIEN      (0x10)    /* RGBC Interrupt Enable */
#define TCS3472_ENABLE_WEN       (0x08)    /* Wait enable - Wbiting 1 activates the wait timer */
#define TCS3472_ENABLE_AEN       (0x02)    /* RGBC Enable - Wbiting 1 actives the ADC, 0 disables it */
#define TCS3472_ENABLE_PON       (0x01)    /* Power on - Wbiting 1 activates the internal oscillator, 0 disables it */
#define TCS3472_ATIME            (0x01)    /* Integration time */
#define TCS3472_WTIME            (0x03)    /* Wait time (if TCS3472_ENABLE_WEN is asserted) */
#define TCS3472_WTIME_2_4MS      (0xFF)    /* WLONG0 = 2.4ms   WLONG1 = 0.029s */
#define TCS3472_WTIME_204MS      (0xAB)    /* WLONG0 = 204ms   WLONG1 = 2.45s  */
#define TCS3472_WTIME_614MS      (0x00)    /* WLONG0 = 614ms   WLONG1 = 7.4s   */
#define TCS3472_AILTL            (0x04)    /* Clear channel lower interrupt threshold */
#define TCS3472_AILTH            (0x05)
#define TCS3472_AIHTL            (0x06)    /* Clear channel upper interrupt threshold */
#define TCS3472_AIHTH            (0x07)
#define TCS3472_PERS             (0x0C)    /* Persistence register - basic SW filtering mechanism for interrupts */
#define TCS3472_PERS_NONE        (0b0000)  /* Every RGBC cycle generates an interrupt                                */
#define TCS3472_PERS_1_CYCLE     (0b0001)  /* 1 clean channel value outside threshold range generates an interrupt   */
#define TCS3472_PERS_2_CYCLE     (0b0010)  /* 2 clean channel values outside threshold range generates an interrupt  */
#define TCS3472_PERS_3_CYCLE     (0b0011)  /* 3 clean channel values outside threshold range generates an interrupt  */
#define TCS3472_PERS_5_CYCLE     (0b0100)  /* 5 clean channel values outside threshold range generates an interrupt  */
#define TCS3472_PERS_10_CYCLE    (0b0101)  /* 10 clean channel values outside threshold range generates an interrupt */
#define TCS3472_PERS_15_CYCLE    (0b0110)  /* 15 clean channel values outside threshold range generates an interrupt */
#define TCS3472_PERS_20_CYCLE    (0b0111)  /* 20 clean channel values outside threshold range generates an interrupt */
#define TCS3472_PERS_25_CYCLE    (0b1000)  /* 25 clean channel values outside threshold range generates an interrupt */
#define TCS3472_PERS_30_CYCLE    (0b1001)  /* 30 clean channel values outside threshold range generates an interrupt */
#define TCS3472_PERS_35_CYCLE    (0b1010)  /* 35 clean channel values outside threshold range generates an interrupt */
#define TCS3472_PERS_40_CYCLE    (0b1011)  /* 40 clean channel values outside threshold range generates an interrupt */
#define TCS3472_PERS_45_CYCLE    (0b1100)  /* 45 clean channel values outside threshold range generates an interrupt */
#define TCS3472_PERS_50_CYCLE    (0b1101)  /* 50 clean channel values outside threshold range generates an interrupt */
#define TCS3472_PERS_55_CYCLE    (0b1110)  /* 55 clean channel values outside threshold range generates an interrupt */
#define TCS3472_PERS_60_CYCLE    (0b1111)  /* 60 clean channel values outside threshold range generates an interrupt */
#define TCS3472_CONFIG           (0x0D)
#define TCS3472_CONFIG_WLONG     (0x02)    /* Choose between short and long (12x) wait times via TCS3472_WTIME */
#define TCS3472_CONTROL          (0x0F)    /* Set the gain level for the sensor */
#define TCS3472_ID               (0x12)    /* 0x44 = TCS34721/TCS3472, 0x4D = TCS34723/TCS34727 */
#define TCS3472_STATUS           (0x13)
#define TCS3472_STATUS_AINT      (0x10)    /* RGBC Clean channel interrupt */
#define TCS3472_STATUS_AVALID    (0x01)    /* Indicates that the RGBC channels have completed an integration cycle */
#define TCS3472_CDATAL           (0x14)    /* Clear channel data */
#define TCS3472_CDATAH           (0x15)
#define TCS3472_RDATAL           (0x16)    /* Red channel data */
#define TCS3472_RDATAH           (0x17)
#define TCS3472_GDATAL           (0x18)    /* Green channel data */
#define TCS3472_GDATAH           (0x19)
#define TCS3472_BDATAL           (0x1A)    /* Blue channel data */
#define TCS3472_BDATAH           (0x1B)

#define TCS3472_GAIN_1X          0x00   /**<  No gain  */
#define TCS3472_GAIN_4X          0x01   /**<  4x gain  */
#define TCS3472_GAIN_16X         0x02   /**<  16x gain */
#define TCS3472_GAIN_60X         0x03   /**<  60x gain */

static ScnsTcs3472Status WB(ScnsTcs3472Enum tcsN,uint8 addr,uint8 data)
{
    addr|=0x80;
    return scnsBspTcs3472Write(tcsN,&addr,1,&data,1);
}

static uint8 RB(ScnsTcs3472Enum tcsN,uint8 addr)
{
    addr|=0x80;
    uint8 data=0;
    scnsBspTcs3472Read(tcsN,&addr,1,&data,1);
    return data;
}

ScnsTcs3472Status scnsTcs3472Init(ScnsTcs3472Enum tcsN)
{
    SCNS_ASSERT_ON_RUN(tcsN<SCNS_TCS3472_MAX);
    scnsCheck(ScnsTcs3472Status,scnsBspTcs3472Init(tcsN),SCNS_TCS3472_STATUS_OK);
    scnsCheckTimeOut(200000,RB(tcsN,TCS3472_ID)==0X4D,SCNS_TCS3472_STATUS_TIME_OUT);
    
    WB(tcsN,TCS3472_ATIME,256-(50/2.4));
    WB(tcsN,TCS3472_CONTROL,TCS3472_GAIN_60X);
    WB(tcsN,TCS3472_ENABLE,TCS3472_ENABLE_PON);
    WB(tcsN,TCS3472_ENABLE,TCS3472_ENABLE_PON|TCS3472_ENABLE_AEN);
    
    scnsCheck(ScnsTcs3472Status,scnsBspTcs3472PostInit(tcsN),SCNS_TCS3472_STATUS_OK);
    rd[tcsN].inited=1;
    return SCNS_TCS3472_STATUS_OK;
}

void scnsTcs3472Interrupt(ScnsTcs3472Enum tcsN)
{
    SCNS_ASSERT_ON_RUN(tcsN<SCNS_TCS3472_MAX);
    if(!rd[tcsN].inited)
        return;
    
    if((RB(tcsN,TCS3472_STATUS)&TCS3472_STATUS_AVALID))
    {
        uint8 tmp[8]={0,0,0,0,0,0,0,0};
        uint8 device=TCS3472_CDATAL|0x80;
        scnsBspTcs3472Read(tcsN,&device,1,tmp,8);
        const uint16 oc=(((uint16)tmp[1])<<8)|((uint16)tmp[0]);
        const uint16 or=(((uint16)tmp[3])<<8)|((uint16)tmp[2]);
        const uint16 og=(((uint16)tmp[5])<<8)|((uint16)tmp[4]);
        const uint16 ob=(((uint16)tmp[7])<<8)|((uint16)tmp[6]);
        
        uint32 r=((uint32)or)*255*255/oc/162;
        uint32 g=((uint32)og)*255*255/oc/255;
        uint32 b=((uint32)ob)*255*255/oc/209;
        r=scnsMin(r,255);
        g=scnsMin(g,255);
        b=scnsMin(b,255);
        scnsTcs3472Result[tcsN].oc=oc;
        scnsTcs3472Result[tcsN].or=or;
        scnsTcs3472Result[tcsN].og=og;
        scnsTcs3472Result[tcsN].ob=ob;
        scnsTcs3472Result[tcsN].r=(uint8)r;
        scnsTcs3472Result[tcsN].g=(uint8)g;
        scnsTcs3472Result[tcsN].b=(uint8)b;
        
        const float wc=(r+g+b);
        scnsTcs3472Result[tcsN].wr=r/wc;
        scnsTcs3472Result[tcsN].wg=g/wc;
        scnsTcs3472Result[tcsN].wb=b/wc;
        
        scnsBspTcs3472ResultUpdate(tcsN);
    }
}

#endif
